#include "StdAfx.hpp"
#include "VariableEditor.hpp"
#include <hash_map>

using namespace common;


//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
// class TwEnumManager

class TwEnumManager
{
public:
	TwEnumManager() : m_UniqueCounter(1) { }

	TwType GetType(const EnumType *enumType);

private:
	typedef stdext::hash_map<const EnumType*, TwType> MapType;
	MapType m_Map;
	uint m_UniqueCounter;

	TwType CreateTwEnumType(const EnumType *enumType);
};

TwEnumManager g_TwEnumManager;

TwType TwEnumManager::GetType(const EnumType *enumType)
{
	MapType::iterator it = m_Map.find(enumType);
	if (it != m_Map.end())
		return it->second;
	else
	{
		TwType twType = CreateTwEnumType(enumType);
		m_Map.insert(MapType::value_type(enumType, twType));
		return twType;
	}
}

TwType TwEnumManager::CreateTwEnumType(const EnumType *enumType)
{
	assert(enumType);
	uint count = enumType->GetCount();
	assert(count);

	STRING_VECTOR names;
	std::vector<TwEnumVal> twEnumVals;
	TwEnumVal tmpEnumVal;
	string tmpS;
	for (uint i = 0; i < count; i++)
	{
		tmpEnumVal.Value = enumType->GetValue(i);
		
		enumType->GetName(tmpS, i);
		names.push_back(tmpS);

		twEnumVals.push_back(tmpEnumVal);
	}

	for (uint i = 0; i < count; i++)
		twEnumVals[i].Label = names[i].c_str();

	string enumName = Format("enum#") % m_UniqueCounter++;
	
	TwType result = TwDefineEnum(enumName.c_str(), &twEnumVals[0], count);
	assert(result);
	return result;
}


//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
// class VariableEditor

uint VariableEditor::m_NextParamIndex = 1;

VariableEditor::VariableEditor()
: m_VarMan(NULL)
, m_Obj(NULL)
, m_Bar(NULL)
, m_ButtonCount(NULL)
{

}

VariableEditor::~VariableEditor()
{
	if (m_Bar)
		TwDeleteBar(m_Bar);
}

void VariableEditor::Init( VariableManager *varMan, IParamObject *obj, const string &title )
{
	m_VarMan = varMan;
	m_Obj = obj;
	
	CreateBar(title);

	uint varCount = m_VarMan->GetVarCount();

	for (uint i = 0; i < varCount; i++)
	{
		Variable *var = m_VarMan->GetVar(i);
		if (!var->IsInvisible())
			InitVar(var);
	}
}

void VariableEditor::AddButton(const string &label, TwCallbackContext *ctx)
{
	if (m_ButtonCount == 0)
		TwAddSeparator(m_Bar, NULL, NULL);

	string name;
	GenerateUniqueName(name);
	string def = Format("label='#'") % label;
	TwAddButton(m_Bar, name.c_str(), GetTwButtonCallback(), ctx, def.c_str());

	m_ButtonCount++;
}

void VariableEditor::CreateBar(const string &title)
{
	GenerateUniqueName(m_BarName);
	m_Bar = TwNewBar(m_BarName.c_str());
	assert(m_Bar);
	int r = TwDefine((Format("# label='#'") % m_BarName % title).str().c_str()); assert(r == 1);
}

template <typename T>
void VariableEditor::FormatIntegerDef( std::string &outName, std::string &outDef, IntegerVariable<T> *var )
{
	FormatDef(outName, outDef, var);
	outDef += Format(" Min=# Max=# Step=#") % var->MinValue % var->MaxValue % var->StepValue;
}

template <typename T>
void VariableEditor::FormatRealDef( std::string &outName, std::string &outDef, RealVariable<T> *var )
{
	FormatDef(outName, outDef, var);
	outDef += Format(" Min=# Max=#") % var->MinValue % var->MaxValue;
	if (var->StepValue != T())
		outDef += Format(" Step=#") % var->StepValue;
	if (var->Precision != 0)
		outDef += Format(" Precision=#") % var->Precision;
}

template <typename T>
void VariableEditor::FormatVecComponentDef(std::string &outName, std::string &outDef, VecVariable<T> *var, int componentIndex, const string &groupName, const string &label)
{
	GenerateUniqueName(outName);
	outDef = Format("group='#' label='#'") % groupName % label;
	if (var->MinValue[componentIndex] !=0.f || var->MaxValue[componentIndex] != 0.f)
		outDef += Format(" Min=# Max=#") % var->MinValue[componentIndex] % var->MaxValue[componentIndex];
	if (var->StepValue != 0.f)
		outDef += Format(" Step=#") % var->StepValue;
	if (var->Precision != 0)
		outDef += Format(" Precision=#") % var->Precision;
}

void VariableEditor::FormatIntComponentDef(std::string &outName, std::string &outDef, int componentIndex, const string &groupName, const string &label, int minVal, int maxVal)
{
	GenerateUniqueName(outName);
	outDef = Format("group='#' label='#'") % groupName % label;
	if (minVal || maxVal)
		outDef += Format(" Min=# Max=#") % minVal % maxVal;
}

template <typename T>
void VariableEditor::InitUintVar(UintVariable<T> *var)
{
	TwCallbackContext *ctx = CreateTwCallbackContext(var);

	string name, def;
	FormatIntegerDef<T>(name, def, var);
	// I won't respect this, because AntTweakBar has a bug of clearing value when in hex mode.
	//if (var->ShowAsHex)
	//	def += " hexa=true";
	
	TwType twType;
	const type_info &typeInfo = typeid(*var);
	if (typeInfo == typeid(Uint8Variable))
		twType = TW_TYPE_UINT8;
	else if (typeInfo == typeid(Uint16Variable))
		twType = TW_TYPE_UINT16;
	else if (typeInfo == typeid(Uint32Variable))
		twType = TW_TYPE_UINT32;
	else
		assert(0);

	if (var->IsReadOnly())
		TwAddVarCB(m_Bar, name.c_str(), twType, NULL, GetTwGetVarCallback(), ctx, def.c_str());
	else
		TwAddVarCB(m_Bar, name.c_str(), twType, GetTwSetVarCallback(), GetTwGetVarCallback(), ctx, def.c_str());
}

template <typename T>
void VariableEditor::InitIntVar(IntVariable<T> *var)
{
	TwCallbackContext *ctx = CreateTwCallbackContext(var);

	string name, def;
	FormatIntegerDef<T>(name, def, var);
	
	TwType twType;
	const type_info &typeInfo = typeid(*var);
	if (typeInfo == typeid(Int8Variable))
		twType = TW_TYPE_INT8;
	else if (typeInfo == typeid(Int16Variable))
		twType = TW_TYPE_INT16;
	else if (typeInfo == typeid(Int32Variable))
		twType = TW_TYPE_INT32;
	else
		assert(0);

	if (var->IsReadOnly())
		TwAddVarCB(m_Bar, name.c_str(), twType, NULL, GetTwGetVarCallback(), ctx, def.c_str());
	else
		TwAddVarCB(m_Bar, name.c_str(), twType, GetTwSetVarCallback(), GetTwGetVarCallback(), ctx, def.c_str());
}

template <typename T>
void VariableEditor::InitRealVar(RealVariable<T> *var)
{
	TwCallbackContext *ctx = CreateTwCallbackContext(var);

	string name, def;
	FormatRealDef<T>(name, def, var);
	
	TwType twType;
	const type_info &typeInfo = typeid(*var);
	if (typeInfo == typeid(FloatVariable))
		twType = TW_TYPE_FLOAT;
	else if (typeInfo == typeid(DoubleVariable))
		twType = TW_TYPE_DOUBLE;
	else
		assert(0);

	if (var->IsReadOnly())
		TwAddVarCB(m_Bar, name.c_str(), twType, NULL, GetTwGetVarCallback(), ctx, def.c_str());
	else
		TwAddVarCB(m_Bar, name.c_str(), twType, GetTwSetVarCallback(), GetTwGetVarCallback(), ctx, def.c_str());
}

void VariableEditor::InitVar( Variable *var )
{
	const type_info &type = typeid(*var);
	
	if (type == typeid(CharVariable))
		InitCharVar((CharVariable*)var);
	else if (type == typeid(BoolVariable))
		InitBoolVar((BoolVariable*)var);
	
	else if (type == typeid(StlStringVariable))
		InitStlStringVar((StlStringVariable*)var);
	else if (type == typeid(FilePathVariable))
		InitFilePathVar((FilePathVariable*)var);
	else if (type == typeid(DirPathVariable))
		InitDirPathVar((DirPathVariable*)var);
	else if (type == typeid(EnumVariable))
		InitEnumVar((EnumVariable*)var);
	else if (type == typeid(TimeVariable))
		InitTimeVar((TimeVariable*)var);
	
	else if (type == typeid(Uint8Variable))
		InitUintVar((Uint8Variable*)var);
	else if (type == typeid(Uint16Variable))
		InitUintVar((Uint16Variable*)var);
	else if (type == typeid(Uint32Variable))
		InitUintVar((Uint32Variable*)var);

	else if (type == typeid(Int8Variable))
		InitIntVar((Int8Variable*)var);
	else if (type == typeid(Int16Variable))
		InitIntVar((Int16Variable*)var);
	else if (type == typeid(Int32Variable))
		InitIntVar((Int32Variable*)var);
	
	else if (type == typeid(FloatVariable))
		InitRealVar((FloatVariable*)var);
	else if (type == typeid(DoubleVariable))
		InitRealVar((DoubleVariable*)var);

	else if (type == typeid(Vec2Variable))
		InitVec2Var((Vec2Variable*)var);
	else if (type == typeid(Vec3Variable))
		InitVec3Var((Vec3Variable*)var);
	else if (type == typeid(Vec4Variable))
		InitVec4Var((Vec4Variable*)var);
	else if (type == typeid(ColorVariable))
		InitColorVar((ColorVariable*)var);
	else if (type == typeid(ColorfVariable))
		InitColorfVar((ColorfVariable*)var);
	else if (type == typeid(QuaternionVariable))
		InitQuaternionVar((QuaternionVariable*)var);
	else if (type == typeid(PointVariable))
		InitPointVar((PointVariable*)var);
	else if (type == typeid(RectVariable))
		InitRectVar((RectVariable*)var);
	else if (type == typeid(RectfVariable))
		InitRectfVar((RectfVariable*)var);
	else if (type == typeid(BoxVariable))
		InitBoxVar((BoxVariable*)var);
	else if (type == typeid(MatrixVariable))
		InitMatrixVar((MatrixVariable*)var);

	else
		InitUnknownVar(var);
}

void VariableEditor::TwSetVar(uint tag, const void *data)
{
	const TwCallbackTag &tagData = m_CallbackTags[tag];
	Variable *var = tagData.m_Var;
	const type_info &type = typeid(*var);

	if (type == typeid(CharVariable))
	{
		CharVariable *varT = (CharVariable*)var;
		// char[2] -> char
		const char *s = (const char*)data;
		varT->SetValue(*m_Obj, s[0]);
	}
	else if (type == typeid(BoolVariable))
	{
		BoolVariable *varT = (BoolVariable*)var;
		const bool *v = (const bool*)data;
		varT->SetValue(*m_Obj, *v);
	}
	else if (type == typeid(StlStringVariable)
		|| type == typeid(FilePathVariable)
		|| type == typeid(DirPathVariable))
	{
		StlStringVariable *varT = (StlStringVariable*)var;
		// std::string (AntTweakBar) -> std::string
		const string *s = (const string*)data;
		varT->SetValue(*m_Obj, *s);
	}
	else if (type == typeid(TimeVariable))
	{
		TimeVariable *varT = (TimeVariable*)var;
		const char *s = (const char*)data;
		varT->LoadFromString(*m_Obj, s);
	}

	else if (type == typeid(Uint8Variable))
	{
		Uint8Variable *varT = (Uint8Variable*)var;
		const uint1 *v = (const uint1*)data;
		varT->SetValue(*m_Obj, *v);
	}
	else if (type == typeid(Uint16Variable))
	{
		Uint16Variable *varT = (Uint16Variable*)var;
		const uint2 *v = (const uint2*)data;
		varT->SetValue(*m_Obj, *v);
	}
	else if (type == typeid(Uint32Variable) || type == typeid(EnumVariable))
	{
		Uint32Variable *varT = (Uint32Variable*)var;
		const uint4 *v = (const uint4*)data;
		varT->SetValue(*m_Obj, *v);
	}

	else if (type == typeid(Int8Variable))
	{
		Int8Variable *varT = (Int8Variable*)var;
		const int1 *v = (const int1*)data;
		varT->SetValue(*m_Obj, *v);
	}
	else if (type == typeid(Int16Variable))
	{
		Int16Variable *varT = (Int16Variable*)var;
		const int2 *v = (const int2*)data;
		varT->SetValue(*m_Obj, *v);
	}
	else if (type == typeid(Int32Variable))
	{
		Int32Variable *varT = (Int32Variable*)var;
		const int4 *v = (const int4*)data;
		varT->SetValue(*m_Obj, *v);
	}

	else if (type == typeid(FloatVariable))
	{
		FloatVariable *varT = (FloatVariable*)var;
		const float *v = (const float*)data;
		varT->SetValue(*m_Obj, *v);
	}
	else if (type == typeid(DoubleVariable))
	{
		DoubleVariable *varT = (DoubleVariable*)var;
		const double *v = (const double*)data;
		varT->SetValue(*m_Obj, *v);
	}
	else if (type == typeid(Vec2Variable))
	{
		Vec2Variable *varT = (Vec2Variable*)var;
		const float *componentVal = (const float*)data;
		VEC2 val;
		varT->GetValue(*m_Obj, val);
		val[tagData.m_Index] = *componentVal;
		varT->SetValue(*m_Obj, val);
	}
	else if (type == typeid(Vec3Variable))
	{
		Vec3Variable *varT = (Vec3Variable*)var;
		if (tagData.m_Index == 0x80000000)
		{
			const VEC3 *v = (const VEC3*)data;
			varT->SetValue(*m_Obj, *v);
		}
		else
		{
			const float *componentVal = (const float*)data;
			VEC3 val;
			varT->GetValue(*m_Obj, val);
			val[tagData.m_Index] = *componentVal;
			varT->SetValue(*m_Obj, val);
		}
	}
	else if (type == typeid(Vec4Variable))
	{
		Vec4Variable *varT = (Vec4Variable*)var;
		const float *componentVal = (const float*)data;
		VEC4 val;
		varT->GetValue(*m_Obj, val);
		val[tagData.m_Index] = *componentVal;
		varT->SetValue(*m_Obj, val);
	}
	else if (type == typeid(ColorVariable))
	{
		ColorVariable *varT = (ColorVariable*)var;
		const COLOR *v = (const COLOR*)data;
		varT->SetValue(*m_Obj, *v);
	}
	else if (type == typeid(ColorfVariable))
	{
		ColorfVariable *varT = (ColorfVariable*)var;
		if (tagData.m_Index) // UseAlpha
		{
			const COLORF *v = (const COLORF*)data;
			varT->SetValue(*m_Obj, *v);
		}
		else
		{
			const VEC3 *twVal = (const VEC3*)data;

			COLORF val;
			val.R = twVal->x;
			val.G = twVal->y;
			val.B = twVal->z;
			val.A = 1.f;
			varT->SetValue(*m_Obj, val);
		}
	}
	else if (type == typeid(QuaternionVariable))
	{
		QuaternionVariable *varT = (QuaternionVariable*)var;
		const QUATERNION *v = (const QUATERNION*)data;
		varT->SetValue(*m_Obj, *v);
	}
	else if (type == typeid(PointVariable))
	{
		PointVariable *varT = (PointVariable*)var;
		const int *componentVal = (const int*)data;
		POINT_ val;
		varT->GetValue(*m_Obj, val);
		val[tagData.m_Index] = *componentVal;
		varT->SetValue(*m_Obj, val);
	}
	else if (type == typeid(RectVariable))
	{
		RectVariable *varT = (RectVariable*)var;
		const int *componentVal = (const int*)data;
		RECTI val;
		varT->GetValue(*m_Obj, val);

		if (tagData.m_Index >> 1)
			val.Max[tagData.m_Index & 1] = *componentVal;
		else
			val.Min[tagData.m_Index & 1] = *componentVal;

		varT->SetValue(*m_Obj, val);
	}
	else if (type == typeid(RectfVariable))
	{
		RectfVariable *varT = (RectfVariable*)var;
		const float *componentVal = (const float*)data;
		RECTF val;
		varT->GetValue(*m_Obj, val);

		if (tagData.m_Index >> 1)
			val.Max[tagData.m_Index & 1] = *componentVal;
		else
			val.Min[tagData.m_Index & 1] = *componentVal;

		varT->SetValue(*m_Obj, val);
	}
	else if (type == typeid(BoxVariable))
	{
		BoxVariable *varT = (BoxVariable*)var;
		const float *componentVal = (const float*)data;
		BOX val;
		varT->GetValue(*m_Obj, val);

		if (tagData.m_Index / 3)
			val.Max[tagData.m_Index % 3] = *componentVal;
		else
			val.Min[tagData.m_Index % 3] = *componentVal;

		varT->SetValue(*m_Obj, val);
	}
	else if (type == typeid(MatrixVariable))
	{
		MatrixVariable *varT = (MatrixVariable*)var;
		const float *componentVal = (const float*)data;
		MATRIX val;
		varT->GetValue(*m_Obj, val);
		((float*)val)[tagData.m_Index] = *componentVal;
		varT->SetValue(*m_Obj, val);
	}

	else
		assert(0);
}

void VariableEditor::TwGetVar(uint tag, void *outData)
{
	const TwCallbackTag &tagData = m_CallbackTags[tag];
	Variable *var = tagData.m_Var;
	const type_info &type = typeid(*var);

	if (type == typeid(CharVariable))
	{
		CharVariable *varT = (CharVariable*)var;
		// char -> char[2]
		char *s = (char*)outData;
		varT->GetValue(*m_Obj, s[0]);
		s[1] = 0;
	}
	else if (type == typeid(BoolVariable))
	{
		BoolVariable *varT = (BoolVariable*)var;
		bool *v = (bool*)outData;
		varT->GetValue(*m_Obj, *v);
	}
	else if (type == typeid(StlStringVariable)
		|| type == typeid(FilePathVariable)
		|| type == typeid(DirPathVariable))
	{
		StlStringVariable *varT = (StlStringVariable*)var;
		// std::string -> std::string (AntTweakBar)
		string s;
		varT->GetValue(*m_Obj, s);
		TwCopyStdStringToLibrary(*(string*)outData, s);
	}
	else if (type == typeid(TimeVariable))
	{
		TimeVariable *varT = (TimeVariable*)var;
		string s;
		varT->SaveToString(*m_Obj, s);
		char *dest = (char*)outData;
		strncpy_s(dest, 32, s.c_str(), 31);
	}

	else if (type == typeid(Uint8Variable))
	{
		Uint8Variable *varT = (Uint8Variable*)var;
		uint1 *v = (uint1*)outData;
		varT->GetValue(*m_Obj, *v);
	}
	else if (type == typeid(Uint16Variable))
	{
		Uint16Variable *varT = (Uint16Variable*)var;
		uint2 *v = (uint2*)outData;
		varT->GetValue(*m_Obj, *v);
	}
	else if (type == typeid(Uint32Variable) || type == typeid(EnumVariable))
	{
		Uint32Variable *varT = (Uint32Variable*)var;
		uint4 *v = (uint4*)outData;
		varT->GetValue(*m_Obj, *v);
	}

	else if (type == typeid(Int8Variable))
	{
		Int8Variable *varT = (Int8Variable*)var;
		int1 *v = (int1*)outData;
		varT->GetValue(*m_Obj, *v);
	}
	else if (type == typeid(Int16Variable))
	{
		Int16Variable *varT = (Int16Variable*)var;
		int2 *v = (int2*)outData;
		varT->GetValue(*m_Obj, *v);
	}
	else if (type == typeid(Int32Variable))
	{
		Int32Variable *varT = (Int32Variable*)var;
		int4 *v = (int4*)outData;
		varT->GetValue(*m_Obj, *v);
	}

	else if (type == typeid(FloatVariable))
	{
		FloatVariable *varT = (FloatVariable*)var;
		float *v = (float*)outData;
		varT->GetValue(*m_Obj, *v);
	}
	else if (type == typeid(DoubleVariable))
	{
		DoubleVariable *varT = (DoubleVariable*)var;
		double *v = (double*)outData;
		varT->GetValue(*m_Obj, *v);
	}
	else if (type == typeid(Vec2Variable))
	{
		Vec2Variable *varT = (Vec2Variable*)var;
		float *componentVal = (float*)outData;
		VEC2 val;
		varT->GetValue(*m_Obj, val);
		*componentVal = val[tagData.m_Index];
	}
	else if (type == typeid(Vec3Variable))
	{
		Vec3Variable *varT = (Vec3Variable*)var;
		if (tagData.m_Index == 0x80000000)
		{
			VEC3 *v = (VEC3*)outData;
			varT->GetValue(*m_Obj, *v);
		}
		else
		{
			float *componentVal = (float*)outData;
			VEC3 val;
			varT->GetValue(*m_Obj, val);
			*componentVal = val[tagData.m_Index];
		}
	}
	else if (type == typeid(Vec4Variable))
	{
		Vec4Variable *varT = (Vec4Variable*)var;
		float *componentVal = (float*)outData;
		VEC4 val;
		varT->GetValue(*m_Obj, val);
		*componentVal = val[tagData.m_Index];
	}
	else if (type == typeid(ColorVariable))
	{
		ColorVariable *varT = (ColorVariable*)var;
		COLOR *v = (COLOR*)outData;
		varT->GetValue(*m_Obj, *v);
	}
	else if (type == typeid(ColorfVariable))
	{
		ColorfVariable *varT = (ColorfVariable*)var;
		if (tagData.m_Index) // UseAlpha
		{
			COLORF *v = (COLORF*)outData;
			varT->GetValue(*m_Obj, *v);
		}
		else
		{
			COLORF val;
			varT->GetValue(*m_Obj, val);

			VEC3 *twVal = (VEC3*)outData;
			twVal->x = val.R;
			twVal->y = val.G;
			twVal->z = val.B;
		}
	}
	else if (type == typeid(QuaternionVariable))
	{
		QuaternionVariable *varT = (QuaternionVariable*)var;
		QUATERNION *v = (QUATERNION*)outData;
		varT->GetValue(*m_Obj, *v);
	}
	else if (type == typeid(PointVariable))
	{
		PointVariable *varT = (PointVariable*)var;
		int *componentVal = (int*)outData;
		POINT_ val;
		varT->GetValue(*m_Obj, val);
		*componentVal = val[tagData.m_Index];
	}
	else if (type == typeid(RectVariable))
	{
		RectVariable *varT = (RectVariable*)var;
		int *componentVal = (int*)outData;
		RECTI val;
		varT->GetValue(*m_Obj, val);
		
		if (tagData.m_Index >> 1)
			*componentVal = val.Max[tagData.m_Index & 1];
		else
			*componentVal = val.Min[tagData.m_Index & 1];
	}
	else if (type == typeid(RectfVariable))
	{
		RectfVariable *varT = (RectfVariable*)var;
		float *componentVal = (float*)outData;
		RECTF val;
		varT->GetValue(*m_Obj, val);
		
		if (tagData.m_Index >> 1)
			*componentVal = val.Max[tagData.m_Index & 1];
		else
			*componentVal = val.Min[tagData.m_Index & 1];
	}
	else if (type == typeid(BoxVariable))
	{
		BoxVariable *varT = (BoxVariable*)var;
		float *componentVal = (float*)outData;
		BOX val;
		varT->GetValue(*m_Obj, val);
		
		if (tagData.m_Index / 3)
			*componentVal = val.Max[tagData.m_Index % 3];
		else
			*componentVal = val.Min[tagData.m_Index % 3];
	}
	else if (type == typeid(MatrixVariable))
	{
		MatrixVariable *varT = (MatrixVariable*)var;
		float *componentVal = (float*)outData;
		MATRIX val;
		varT->GetValue(*m_Obj, val);
		*componentVal = ((const float*)val)[tagData.m_Index];
	}

	else
		assert(0);
}

void VariableEditor::TwButton(uint tag)
{
	const TwCallbackTag &tagData = m_CallbackTags[tag];
	Variable *var = tagData.m_Var;
	const type_info &type = typeid(*var);
	if (type == typeid(FilePathVariable))
	{
		FilePathVariable *varT = (FilePathVariable*)var;
		string newPath;
		if (BrowseableFileType::ShowOpenDialog(newPath, varT->FileType))
			varT->SetValue(*m_Obj, newPath);
	}
	else if (type == typeid(DirPathVariable))
	{
		DirPathVariable *varT = (DirPathVariable*)var;
		string dir;
		varT->GetValue(*m_Obj, dir);
		if (DirPathVariable::ShowDirDialog(dir, var->GetName()))
			varT->SetValue(*m_Obj, dir);
	}
	else
		assert(0);
}

void VariableEditor::InitUnknownVar( Variable *var )
{
	TwCallbackContext *ctx = CreateTwCallbackContext(var);

	string name, def;
	FormatDef(name, def, var);

	const char *typeName = var->GetTypeName();
	uint len = strlen(typeName)+3;
	char *sz = new char[len+1];
	sprintf_s(sz, len, "(%s)", typeName);
	m_HelperStrings.push_back(CharArraySharedPtr(sz));
	TwAddVarRO(m_Bar, name.c_str(), TW_TYPE_CSSTRING(len), sz, def.c_str());
}

void VariableEditor::InitCharVar(CharVariable *var)
{
	TwCallbackContext *ctx = CreateTwCallbackContext(var);

	string name, def;
	FormatDef(name, def, var);

	if (var->IsReadOnly())
		TwAddVarCB(m_Bar, name.c_str(), TW_TYPE_CSSTRING(2), NULL, GetTwGetVarCallback(), ctx, def.c_str());
	else
		TwAddVarCB(m_Bar, name.c_str(), TW_TYPE_CSSTRING(2), GetTwSetVarCallback(), GetTwGetVarCallback(), ctx, def.c_str());
}

void VariableEditor::InitBoolVar(BoolVariable *var)
{
	TwCallbackContext *ctx = CreateTwCallbackContext(var);

	string name, def;
	FormatDef(name, def, var);

	if (var->IsReadOnly())
		TwAddVarCB(m_Bar, name.c_str(), TW_TYPE_BOOLCPP, NULL, GetTwGetVarCallback(), ctx, def.c_str());
	else
		TwAddVarCB(m_Bar, name.c_str(), TW_TYPE_BOOLCPP, GetTwSetVarCallback(), GetTwGetVarCallback(), ctx, def.c_str());
}

void VariableEditor::InitStlStringVar(StlStringVariable *var)
{
	TwCallbackContext *ctx = CreateTwCallbackContext(var);

	string name, def;
	FormatDef(name, def, var);

	if (var->IsReadOnly())
		TwAddVarCB(m_Bar, name.c_str(), TW_TYPE_STDSTRING, NULL, GetTwGetVarCallback(), ctx, def.c_str());
	else
		TwAddVarCB(m_Bar, name.c_str(), TW_TYPE_STDSTRING, GetTwSetVarCallback(), GetTwGetVarCallback(), ctx, def.c_str());
}

void VariableEditor::InitFilePathVar(FilePathVariable *var)
{
	TwCallbackContext *ctx = CreateTwCallbackContext(var);

	string groupName, itemName;
	GenerateUniqueName(groupName);
	GenerateUniqueName(itemName);

	string def = Format("group='#' label='Path'") % groupName;
	
	if (var->IsReadOnly())
		TwAddVarCB(m_Bar, itemName.c_str(), TW_TYPE_STDSTRING, NULL, GetTwGetVarCallback(), ctx, def.c_str());
	else
	{
		TwAddVarCB(m_Bar, itemName.c_str(), TW_TYPE_STDSTRING, GetTwSetVarCallback(), GetTwGetVarCallback(), ctx, def.c_str());
		GenerateUniqueName(itemName);
		def = Format("group='#' label='Browse...'") % groupName;
		TwAddButton(m_Bar, itemName.c_str(), GetTwButtonCallback(), ctx, def.c_str());
	}

	def = Format("#/# label='#' close") % m_BarName % groupName % var->GetName();
	TwDefine(def.c_str());
}

void VariableEditor::InitDirPathVar(DirPathVariable *var)
{
	TwCallbackContext *ctx = CreateTwCallbackContext(var);

	string groupName, itemName;
	GenerateUniqueName(groupName);
	GenerateUniqueName(itemName);

	string def = Format("group='#' label='Path'") % groupName;
	
	if (var->IsReadOnly())
		TwAddVarCB(m_Bar, itemName.c_str(), TW_TYPE_STDSTRING, NULL, GetTwGetVarCallback(), ctx, def.c_str());
	else
	{
		TwAddVarCB(m_Bar, itemName.c_str(), TW_TYPE_STDSTRING, GetTwSetVarCallback(), GetTwGetVarCallback(), ctx, def.c_str());
		GenerateUniqueName(itemName);
		def = Format("group='#' label='Browse...'") % groupName;
		TwAddButton(m_Bar, itemName.c_str(), GetTwButtonCallback(), ctx, def.c_str());
	}

	def = Format("#/# label='#' close") % m_BarName % groupName % var->GetName();
	TwDefine(def.c_str());
}

void VariableEditor::InitEnumVar(EnumVariable *var)
{
	TwCallbackContext *ctx = CreateTwCallbackContext(var);

	if (var->m_EnumType == NULL || var->m_EnumType->GetCount() == 0)
	{
		InitUintVar<uint4>(var);
		return;
	}

	string name, def;
	FormatDef(name, def, var);

	TwType twType = g_TwEnumManager.GetType(var->m_EnumType);

	if (var->IsReadOnly())
		TwAddVarCB(m_Bar, name.c_str(), twType, NULL, GetTwGetVarCallback(), ctx, def.c_str());
	else
		TwAddVarCB(m_Bar, name.c_str(), twType, GetTwSetVarCallback(), GetTwGetVarCallback(), ctx, def.c_str());
}

void VariableEditor::InitTimeVar(TimeVariable *var)
{
	TwCallbackContext *ctx = CreateTwCallbackContext(var);

	string name, def;
	FormatDef(name, def, var);

	if (var->IsReadOnly())
		TwAddVarCB(m_Bar, name.c_str(), TW_TYPE_CSSTRING(32), NULL, GetTwGetVarCallback(), ctx, def.c_str());
	else
		TwAddVarCB(m_Bar, name.c_str(), TW_TYPE_CSSTRING(32), GetTwSetVarCallback(), GetTwGetVarCallback(), ctx, def.c_str());
}

void VariableEditor::InitVec2Var(Vec2Variable *var)
{
	TwCallbackContext *ctxs[2] = {
		CreateTwCallbackContext(var, 0),
		CreateTwCallbackContext(var, 1),
	};

	string groupName, itemNames[2], itemDefs[2];
	GenerateUniqueName(groupName);
	FormatVecComponentDef(itemNames[0], itemDefs[0], var, 0, groupName, "x");
	FormatVecComponentDef(itemNames[1], itemDefs[1], var, 1, groupName, "y");

	if (var->IsReadOnly())
	{
		TwAddVarCB(m_Bar, itemNames[0].c_str(), TW_TYPE_FLOAT, NULL, GetTwGetVarCallback(), ctxs[0], itemDefs[0].c_str());
		TwAddVarCB(m_Bar, itemNames[1].c_str(), TW_TYPE_FLOAT, NULL, GetTwGetVarCallback(), ctxs[1], itemDefs[1].c_str());
	}
	else
	{
		TwAddVarCB(m_Bar, itemNames[0].c_str(), TW_TYPE_FLOAT, GetTwSetVarCallback(), GetTwGetVarCallback(), ctxs[0], itemDefs[0].c_str());
		TwAddVarCB(m_Bar, itemNames[1].c_str(), TW_TYPE_FLOAT, GetTwSetVarCallback(), GetTwGetVarCallback(), ctxs[1], itemDefs[1].c_str());
	}

	string groupDef = Format("#/# label='#' close") % m_BarName % groupName % var->GetName();
	TwDefine(groupDef.c_str());
}

void VariableEditor::InitVec3Var(Vec3Variable *var)
{
	if (var->IsDirection)
	{
		TwCallbackContext *ctx = CreateTwCallbackContext(var, 0x80000000);

		string name, def;
		FormatDef(name, def, var);

		if (var->IsReadOnly())
			TwAddVarCB(m_Bar, name.c_str(), TW_TYPE_DIR3F, NULL, GetTwGetVarCallback(), ctx, def.c_str());
		else
			TwAddVarCB(m_Bar, name.c_str(), TW_TYPE_DIR3F, GetTwSetVarCallback(), GetTwGetVarCallback(), ctx, def.c_str());
	}
	else
	{
		TwCallbackContext *ctxs[3] = {
			CreateTwCallbackContext(var, 0),
			CreateTwCallbackContext(var, 1),
			CreateTwCallbackContext(var, 2),
		};

		string groupName, itemNames[3], itemDefs[3];
		GenerateUniqueName(groupName);
		FormatVecComponentDef(itemNames[0], itemDefs[0], var, 0, groupName, "x");
		FormatVecComponentDef(itemNames[1], itemDefs[1], var, 1, groupName, "y");
		FormatVecComponentDef(itemNames[2], itemDefs[2], var, 2, groupName, "z");

		if (var->IsReadOnly())
		{
			TwAddVarCB(m_Bar, itemNames[0].c_str(), TW_TYPE_FLOAT, NULL, GetTwGetVarCallback(), ctxs[0], itemDefs[0].c_str());
			TwAddVarCB(m_Bar, itemNames[1].c_str(), TW_TYPE_FLOAT, NULL, GetTwGetVarCallback(), ctxs[1], itemDefs[1].c_str());
			TwAddVarCB(m_Bar, itemNames[2].c_str(), TW_TYPE_FLOAT, NULL, GetTwGetVarCallback(), ctxs[2], itemDefs[2].c_str());
		}
		else
		{
			TwAddVarCB(m_Bar, itemNames[0].c_str(), TW_TYPE_FLOAT, GetTwSetVarCallback(), GetTwGetVarCallback(), ctxs[0], itemDefs[0].c_str());
			TwAddVarCB(m_Bar, itemNames[1].c_str(), TW_TYPE_FLOAT, GetTwSetVarCallback(), GetTwGetVarCallback(), ctxs[1], itemDefs[1].c_str());
			TwAddVarCB(m_Bar, itemNames[2].c_str(), TW_TYPE_FLOAT, GetTwSetVarCallback(), GetTwGetVarCallback(), ctxs[2], itemDefs[2].c_str());
		}

		string groupDef = Format("#/# label='#' close") % m_BarName % groupName % var->GetName();
		TwDefine(groupDef.c_str());
	}
}

void VariableEditor::InitVec4Var(Vec4Variable *var)
{
	TwCallbackContext *ctxs[4] = {
		CreateTwCallbackContext(var, 0),
		CreateTwCallbackContext(var, 1),
		CreateTwCallbackContext(var, 2),
		CreateTwCallbackContext(var, 3),
	};

	string groupName, itemNames[4], itemDefs[4];
	GenerateUniqueName(groupName);
	FormatVecComponentDef(itemNames[0], itemDefs[0], var, 0, groupName, "x");
	FormatVecComponentDef(itemNames[1], itemDefs[1], var, 1, groupName, "y");
	FormatVecComponentDef(itemNames[2], itemDefs[2], var, 2, groupName, "z");
	FormatVecComponentDef(itemNames[3], itemDefs[3], var, 3, groupName, "w");

	if (var->IsReadOnly())
	{
		TwAddVarCB(m_Bar, itemNames[0].c_str(), TW_TYPE_FLOAT, NULL, GetTwGetVarCallback(), ctxs[0], itemDefs[0].c_str());
		TwAddVarCB(m_Bar, itemNames[1].c_str(), TW_TYPE_FLOAT, NULL, GetTwGetVarCallback(), ctxs[1], itemDefs[1].c_str());
		TwAddVarCB(m_Bar, itemNames[2].c_str(), TW_TYPE_FLOAT, NULL, GetTwGetVarCallback(), ctxs[2], itemDefs[2].c_str());
		TwAddVarCB(m_Bar, itemNames[3].c_str(), TW_TYPE_FLOAT, NULL, GetTwGetVarCallback(), ctxs[3], itemDefs[3].c_str());
	}
	else
	{
		TwAddVarCB(m_Bar, itemNames[0].c_str(), TW_TYPE_FLOAT, GetTwSetVarCallback(), GetTwGetVarCallback(), ctxs[0], itemDefs[0].c_str());
		TwAddVarCB(m_Bar, itemNames[1].c_str(), TW_TYPE_FLOAT, GetTwSetVarCallback(), GetTwGetVarCallback(), ctxs[1], itemDefs[1].c_str());
		TwAddVarCB(m_Bar, itemNames[2].c_str(), TW_TYPE_FLOAT, GetTwSetVarCallback(), GetTwGetVarCallback(), ctxs[2], itemDefs[2].c_str());
		TwAddVarCB(m_Bar, itemNames[3].c_str(), TW_TYPE_FLOAT, GetTwSetVarCallback(), GetTwGetVarCallback(), ctxs[3], itemDefs[3].c_str());
	}

	string groupDef = Format("#/# label='#' close") % m_BarName % groupName % var->GetName();
	TwDefine(groupDef.c_str());
}

void VariableEditor::InitColorVar(ColorVariable *var)
{
	TwCallbackContext *ctx = CreateTwCallbackContext(var);

	string name, def;
	FormatDef(name, def, var);
	if (var->UseAlpha)
		def += " alpha";

	if (var->IsReadOnly())
		TwAddVarCB(m_Bar, name.c_str(), TW_TYPE_COLOR32, NULL, GetTwGetVarCallback(), ctx, def.c_str());
	else
		TwAddVarCB(m_Bar, name.c_str(), TW_TYPE_COLOR32, GetTwSetVarCallback(), GetTwGetVarCallback(), ctx, def.c_str());
}

void VariableEditor::InitColorfVar(ColorfVariable *var)
{
	TwCallbackContext *ctx = CreateTwCallbackContext(var, var->UseAlpha ? 1 : 0);

	string name, def;
	FormatDef(name, def, var);

	TwType twType = var->UseAlpha ? TW_TYPE_COLOR4F : TW_TYPE_COLOR3F;

	if (var->IsReadOnly())
		TwAddVarCB(m_Bar, name.c_str(), twType, NULL, GetTwGetVarCallback(), ctx, def.c_str());
	else
		TwAddVarCB(m_Bar, name.c_str(), twType, GetTwSetVarCallback(), GetTwGetVarCallback(), ctx, def.c_str());
}

void VariableEditor::InitQuaternionVar(QuaternionVariable *var)
{
	TwCallbackContext *ctx = CreateTwCallbackContext(var);

	string name, def;
	FormatDef(name, def, var);

	if (var->IsReadOnly())
		TwAddVarCB(m_Bar, name.c_str(), TW_TYPE_QUAT4F, NULL, GetTwGetVarCallback(), ctx, def.c_str());
	else
		TwAddVarCB(m_Bar, name.c_str(), TW_TYPE_QUAT4F, GetTwSetVarCallback(), GetTwGetVarCallback(), ctx, def.c_str());
}

void VariableEditor::InitPointVar(PointVariable *var)
{
	TwCallbackContext *ctxs[2] = {
		CreateTwCallbackContext(var, 0),
		CreateTwCallbackContext(var, 1),
	};

	string groupName, itemNames[2], itemDefs[2];
	GenerateUniqueName(groupName);
	FormatIntComponentDef(itemNames[0], itemDefs[0], 0, groupName, "x", var->MinValue.x, var->MaxValue.x);
	FormatIntComponentDef(itemNames[1], itemDefs[1], 1, groupName, "y", var->MinValue.y, var->MaxValue.y);

	if (var->IsReadOnly())
	{
		TwAddVarCB(m_Bar, itemNames[0].c_str(), TW_TYPE_INT32, NULL, GetTwGetVarCallback(), ctxs[0], itemDefs[0].c_str());
		TwAddVarCB(m_Bar, itemNames[1].c_str(), TW_TYPE_INT32, NULL, GetTwGetVarCallback(), ctxs[1], itemDefs[1].c_str());
	}
	else
	{
		TwAddVarCB(m_Bar, itemNames[0].c_str(), TW_TYPE_INT32, GetTwSetVarCallback(), GetTwGetVarCallback(), ctxs[0], itemDefs[0].c_str());
		TwAddVarCB(m_Bar, itemNames[1].c_str(), TW_TYPE_INT32, GetTwSetVarCallback(), GetTwGetVarCallback(), ctxs[1], itemDefs[1].c_str());
	}

	string groupDef = Format("#/# label='#' close") % m_BarName % groupName % var->GetName();
	TwDefine(groupDef.c_str());
}

void VariableEditor::InitRectVar(RectVariable *var)
{
	TwCallbackContext *ctxs[4] = {
		CreateTwCallbackContext(var, 0),
		CreateTwCallbackContext(var, 1),
		CreateTwCallbackContext(var, 2),
		CreateTwCallbackContext(var, 3),
	};

	string groupName, itemNames[4], itemDefs[4];
	GenerateUniqueName(groupName);
	FormatIntComponentDef(itemNames[0], itemDefs[0], 0, groupName, "Min x", var->MinValue.x, var->MaxValue.x);
	FormatIntComponentDef(itemNames[1], itemDefs[1], 1, groupName, "Min y", var->MinValue.y, var->MaxValue.y);
	FormatIntComponentDef(itemNames[2], itemDefs[2], 2, groupName, "Max x", var->MinValue.x, var->MaxValue.x);
	FormatIntComponentDef(itemNames[3], itemDefs[3], 3, groupName, "Max y", var->MinValue.y, var->MaxValue.y);

	if (var->IsReadOnly())
	{
		TwAddVarCB(m_Bar, itemNames[0].c_str(), TW_TYPE_INT32, NULL, GetTwGetVarCallback(), ctxs[0], itemDefs[0].c_str());
		TwAddVarCB(m_Bar, itemNames[1].c_str(), TW_TYPE_INT32, NULL, GetTwGetVarCallback(), ctxs[1], itemDefs[1].c_str());
		TwAddVarCB(m_Bar, itemNames[2].c_str(), TW_TYPE_INT32, NULL, GetTwGetVarCallback(), ctxs[2], itemDefs[2].c_str());
		TwAddVarCB(m_Bar, itemNames[3].c_str(), TW_TYPE_INT32, NULL, GetTwGetVarCallback(), ctxs[3], itemDefs[3].c_str());
	}
	else
	{
		TwAddVarCB(m_Bar, itemNames[0].c_str(), TW_TYPE_INT32, GetTwSetVarCallback(), GetTwGetVarCallback(), ctxs[0], itemDefs[0].c_str());
		TwAddVarCB(m_Bar, itemNames[1].c_str(), TW_TYPE_INT32, GetTwSetVarCallback(), GetTwGetVarCallback(), ctxs[1], itemDefs[1].c_str());
		TwAddVarCB(m_Bar, itemNames[2].c_str(), TW_TYPE_INT32, GetTwSetVarCallback(), GetTwGetVarCallback(), ctxs[2], itemDefs[2].c_str());
		TwAddVarCB(m_Bar, itemNames[3].c_str(), TW_TYPE_INT32, GetTwSetVarCallback(), GetTwGetVarCallback(), ctxs[3], itemDefs[3].c_str());
	}

	string groupDef = Format("#/# label='#' close") % m_BarName % groupName % var->GetName();
	TwDefine(groupDef.c_str());
}

void VariableEditor::InitRectfVar(RectfVariable *var)
{
	TwCallbackContext *ctxs[4] = {
		CreateTwCallbackContext(var, 0),
		CreateTwCallbackContext(var, 1),
		CreateTwCallbackContext(var, 2),
		CreateTwCallbackContext(var, 3),
	};

	static const char * LABELS[] = {
		"Min x", "Min y", "Max x", "Max y",
	};

	string groupName, itemNames[4], itemDefs[4];
	GenerateUniqueName(groupName);
	for (uint i = 0; i < 4; i++)
	{
		GenerateUniqueName(itemNames[i]);
		itemDefs[i] = string(" label='") + LABELS[i] + "' group='" + groupName + "' ";
	}

	if (var->IsReadOnly())
	{
		TwAddVarCB(m_Bar, itemNames[0].c_str(), TW_TYPE_FLOAT, NULL, GetTwGetVarCallback(), ctxs[0], itemDefs[0].c_str());
		TwAddVarCB(m_Bar, itemNames[1].c_str(), TW_TYPE_FLOAT, NULL, GetTwGetVarCallback(), ctxs[1], itemDefs[1].c_str());
		TwAddVarCB(m_Bar, itemNames[2].c_str(), TW_TYPE_FLOAT, NULL, GetTwGetVarCallback(), ctxs[2], itemDefs[2].c_str());
		TwAddVarCB(m_Bar, itemNames[3].c_str(), TW_TYPE_FLOAT, NULL, GetTwGetVarCallback(), ctxs[3], itemDefs[3].c_str());
	}
	else
	{
		TwAddVarCB(m_Bar, itemNames[0].c_str(), TW_TYPE_FLOAT, GetTwSetVarCallback(), GetTwGetVarCallback(), ctxs[0], itemDefs[0].c_str());
		TwAddVarCB(m_Bar, itemNames[1].c_str(), TW_TYPE_FLOAT, GetTwSetVarCallback(), GetTwGetVarCallback(), ctxs[1], itemDefs[1].c_str());
		TwAddVarCB(m_Bar, itemNames[2].c_str(), TW_TYPE_FLOAT, GetTwSetVarCallback(), GetTwGetVarCallback(), ctxs[2], itemDefs[2].c_str());
		TwAddVarCB(m_Bar, itemNames[3].c_str(), TW_TYPE_FLOAT, GetTwSetVarCallback(), GetTwGetVarCallback(), ctxs[3], itemDefs[3].c_str());
	}

	string groupDef = Format("#/# label='#' close") % m_BarName % groupName % var->GetName();
	TwDefine(groupDef.c_str());
}

void VariableEditor::InitBoxVar(BoxVariable *var)
{
	TwCallbackContext *ctxs[6] = {
		CreateTwCallbackContext(var, 0),
		CreateTwCallbackContext(var, 1),
		CreateTwCallbackContext(var, 2),
		CreateTwCallbackContext(var, 3),
		CreateTwCallbackContext(var, 4),
		CreateTwCallbackContext(var, 5),
	};

	static const char * LABELS[] = {
		"Min x", "Min y", "Min z", "Max x", "Max y", "Max z",
	};

	string groupName, itemNames[6], itemDefs[6];
	GenerateUniqueName(groupName);
	for (uint i = 0; i < 6; i++)
	{
		GenerateUniqueName(itemNames[i]);
		itemDefs[i] = string(" label='") + LABELS[i] + "' group='" + groupName + "' ";
	}

	if (var->IsReadOnly())
	{
		for (uint i = 0; i < 6; i++)
			TwAddVarCB(m_Bar, itemNames[i].c_str(), TW_TYPE_FLOAT, NULL, GetTwGetVarCallback(), ctxs[i], itemDefs[i].c_str());
	}
	else
	{
		for (uint i = 0; i < 6; i++)
			TwAddVarCB(m_Bar, itemNames[i].c_str(), TW_TYPE_FLOAT, GetTwSetVarCallback(), GetTwGetVarCallback(), ctxs[i], itemDefs[i].c_str());
	}

	string groupDef = Format("#/# label='#' close") % m_BarName % groupName % var->GetName();
	TwDefine(groupDef.c_str());
}

void VariableEditor::InitMatrixVar(MatrixVariable *var)
{
	if (var->EnableFlags == 0)
		return;

	TwCallbackContext *ctxs[16];
	for (uint i = 0; i < 16; i++)
		ctxs[i] = CreateTwCallbackContext(var, i);

	string groupName, itemNames[16], itemDefs[16];
	GenerateUniqueName(groupName);
	for (uint i = 0; i < 16; i++)
	{
		GenerateUniqueName(itemNames[i]);
		itemDefs[i] = Format("group='#' label='#,#'") % groupName % (i/4+1) % (i%4+1);
	}

	for (uint i = 0; i < 16; i++)
	{
		if (MatrixVariable::IsCellEnabled(var->EnableFlags, i/4, i%4))
		{
			if (var->IsReadOnly())
				TwAddVarCB(m_Bar, itemNames[i].c_str(), TW_TYPE_FLOAT, NULL, GetTwGetVarCallback(), ctxs[i], itemDefs[i].c_str());
			else
				TwAddVarCB(m_Bar, itemNames[i].c_str(), TW_TYPE_FLOAT, GetTwSetVarCallback(), GetTwGetVarCallback(), ctxs[i], itemDefs[i].c_str());
		}
	}

	string groupDef = Format("#/# label='#' close") % m_BarName % groupName % var->GetName();
	TwDefine(groupDef.c_str());
}

void VariableEditor::FormatDef( std::string &outName, std::string &outDef, Variable *var )
{
	GenerateUniqueName(outName);
	outDef = " label='" + var->GetName() + "' ";
}

void VariableEditor::GenerateUniqueName(std::string &out)
{
	out = "p" + UintToStrR(m_NextParamIndex++, 16);
}

TwCallbackContext * VariableEditor::CreateTwCallbackContext(Variable *var, uint index)
{
	m_CallbackTags.push_back(TwCallbackTag(var, index));
	uint tag = m_CallbackTags.size()-1;
	m_CallbackContexts.push_back(TwCallbackContext(this, tag));
	return &m_CallbackContexts.back();
}
